#include <stdio.h>
#include <string.h>
#include <mad.h>
#include <pthread.h>
#include <termios.h>
#include <unistd.h>
#include <stdbool.h>
#include <signal.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <time.h>
#include <math.h>

#include "logger.h"
#include "pcm-player.h"
#include "list-files.h"
#include "mp3-parse-id3v2.h"
#include "mp3-info.h"

#include <headset.h>

#ifndef PLAYER_VERSION
#define PLAYER_VERSION "0.0.1"
#endif

// 控制命令
typedef enum ctrl_cmd {
    CTRL_CMD_NONE = 0,
    CTRL_CMD_NEXT = 1,
    CTRL_CMD_PREV = 2,
    CTRL_CMD_PLAY = 3,
    CTRL_CMD_PAUSE = 4,
    CTRL_CMD_STOP = 5,
    CTRL_CMD_VOLUME_UP = 6,
    CTRL_CMD_VOLUME_DOWN = 7,
    CTRL_CMD_FAST_FORWARD = 8,
    CTRL_CMD_FAST_BACKWARD = 9
} ctrl_cmd_t;

typedef enum ctrl_cmd_ret {
    CTRL_CMD_RET_NONE = 0,
    CTRL_CMD_RET_OK = 1,
    CTRL_CMD_RET_ERR = 2
} ctrl_cmd_ret_t;


typedef struct ctrl { 
    ctrl_cmd_t cmd;                     // 控制命令
    ctrl_cmd_ret_t cmd_ret;             // 控制命令返回值
    //int volume;                       // 音量
    pthread_mutex_t cmd_mutex;          // 互斥锁
    pthread_cond_t  cmd_play_cond;       // 播放条件变量
    pthread_mutex_t cmd_ret_mutex;      // 互斥锁
    pthread_cond_t cmd_ret_cond;        // 按键条件变量
    pthread_mutex_t set_volume_mutex;   // 互斥锁
} ctrl_t; 

typedef struct mp3_files {
    char **files;             // MP3文件列表
    int    count;             // MP3文件数量
} mp3_files_t;

typedef struct player_state {
    bool is_playing;         // 是否正在播放
    int current_mp3_no;      // 当前播放的MP3文件索引
    mp3_info_t mp3_info;     // 当前Mp3文件信息
    id3v2_important_info_t id3v2_info; //ID3v2信息
    int current_mp3_ms;          // 当前Mp3播放时间（ms）
    int volume;              // 当前音量
    bool mute;               // 静音
} player_state_t;

typedef struct sys_state {
    struct termios original_termios;    // 保存原始终端设置
    struct winsize scrsize;             // 终端窗口大小
    pcm_player_t **pcm_players;         // PCM设备列表
    int pcm_players_count;              // PCM设备数量
    pcm_player_t *current_pcm_player;   // 当前PCM设备
    int menu_selected_mp3_no;          // 菜单选择MP3 文件索引
    pthread_mutex_t display_mutex;      // 显示互斥锁
} sys_state_t;

typedef struct control_thread {
    pthread_t id;  // 控制线程ID
    pthread_t id2; // 备用控制线程ID
    void *(* func)(void *); // 控制线程函数
    void *(* func2)(void *); // 备用控制线程函数
    volatile sig_atomic_t exit_flag;  // 控制线程退出标志
} control_thread_t;


static mp3_files_t mp3_files = {0};  // MP3文件列表

static ctrl_t ctrl = {
    .cmd = CTRL_CMD_PLAY,
    .cmd_ret = CTRL_CMD_RET_NONE,
    .cmd_mutex = PTHREAD_MUTEX_INITIALIZER,
    .cmd_play_cond = PTHREAD_COND_INITIALIZER,
    .cmd_ret_mutex = PTHREAD_MUTEX_INITIALIZER,
    .set_volume_mutex = PTHREAD_MUTEX_INITIALIZER,
};

static player_state_t  player_state = {
    .is_playing = true,
    .current_mp3_no = 0,
    .mp3_info = {0},
    .id3v2_info = {0},
    .current_mp3_ms = 0,
    .volume = 0,
};

static sys_state_t sys_state = {
    .original_termios = {0},
    .scrsize = {0},
    .pcm_players = NULL,
    .pcm_players_count = 0,
    .current_pcm_player = NULL,
};


// 跨平台延时函数
static void delay_ms(int ms) {
    usleep(ms * 1000); // Linux 和 macOS 使用 usleep()，单位是微秒
 }

#define control_thread_created()  (control_thread.id != ((pthread_t)(-1)))

static void* control_thread_func(void *arg);
static void* control_thread_func2(void *arg);

static control_thread_t control_thread = {
    .id = ((pthread_t)(-1)),
    .id2 = ((pthread_t)(-1)),
    .func = control_thread_func,
    .func2 = control_thread_func2,
    .exit_flag = 0,
};

//==============================================================================
// 信号处理函数
static inline signed int scale(mad_fixed_t sample) {
    /* round */
    sample += (1L << (MAD_F_FRACBITS - 16));

    /* clip */
    if (sample >= MAD_F_ONE)
        sample = MAD_F_ONE - 1;
    else if (sample < -MAD_F_ONE)
        sample = -MAD_F_ONE;

    /* quantize */
    return sample >> (MAD_F_FRACBITS + 1 - 16);
}



static int init_screen(void) {
    int rc = 0;
    pthread_mutex_lock(&sys_state.display_mutex);
    //获取终端的行数和列数
    struct winsize *ss = &sys_state.scrsize;
    ioctl(STDIN_FILENO, TIOCGWINSZ, ss);
    if(ss->ws_col <= 0 || ss->ws_row <= 0) {
        ilog("ioctl TIOCGWINSZ failed, set to default %dx%d\n", 80, 24);
        ss->ws_col = 80;
        ss->ws_row = 24;
    }
    if(ss->ws_row < UI_MIN_HEIGHT || ss->ws_col < UI_MIN_WIDTH) {
        elog("Terminal size %dx%d is too small, minimum size is %dx%d\n", ss->ws_col, ss->ws_row, UI_MIN_WIDTH, UI_MIN_HEIGHT);
        rc = -1;
        goto _end;
    }
    printf("\033[2J"); // 清屏
    //滚动区域设置为倒数第5行到结束
    printf("\033[%d;%dr", ss->ws_row - UI_HEIGHT_LOG , ss->ws_row);
    //光标移动到LOG区域
    printf("\033[%d;1H",  ss->ws_row - UI_HEIGHT_LOG);
    ilog("screen size: %d rows, %d columns\n", ss->ws_row, ss->ws_col);
    fflush(stdout);
_end:
    pthread_mutex_unlock(&sys_state.display_mutex);
    return rc;
}

static int deinit_screen(void) {
    // 恢复滚动区域到默认
    printf("\033[s\033[r\033[u"); // 恢复滚动区域到默认, 恢复光标位置
    // 恢复光标显示
    printf("\033[?25h");
    fflush(stdout);
    return 0;
}


static void sigwinch_handler(int sig);

static void deinit(void);

// 初始化
static int init(void) {
    // 初始化屏幕
    int rc = init_screen(); 
    if(rc != 0) {
        elog("init_screen failed\n");
        return rc;
    }

    // 保存原始终端设置
    struct termios new_termios;
    tcgetattr(STDIN_FILENO, &sys_state.original_termios);
    new_termios = sys_state.original_termios;

    // 关闭标准输入模式和回显, 禁止信号
    new_termios.c_lflag &= ~(ICANON | ECHO | ISIG);  // 关闭标准输入模式和回显, 禁止信号
    tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);


    // 注册信号处理函数
    signal(SIGWINCH, sigwinch_handler);

    // 初始化互斥锁和条件变量
    pthread_mutex_init(&ctrl.cmd_mutex, NULL);
    pthread_mutex_init(&ctrl.cmd_ret_mutex, NULL);
    pthread_cond_init(&ctrl.cmd_play_cond, NULL);  
    pthread_cond_init(&ctrl.cmd_ret_cond, NULL);
    pthread_mutex_init(&ctrl.set_volume_mutex, NULL);
    pthread_mutex_init(&sys_state.display_mutex, NULL);
    // 在程序退出时恢复终端设置
    atexit(deinit);
    return 0;
}

// 恢复
void deinit(void) {
    // 恢复终端设置
    tcsetattr(STDIN_FILENO, TCSANOW, &sys_state.original_termios);

    // 注销信号处理函数
    signal(SIGWINCH, SIG_DFL);
    // 恢复屏幕
    deinit_screen();

    // 销毅互斥锁和条件变量
    pthread_mutex_destroy(&ctrl.cmd_mutex);
    pthread_mutex_destroy(&ctrl.cmd_ret_mutex);
    pthread_cond_destroy(&ctrl.cmd_play_cond);
    pthread_cond_destroy(&ctrl.cmd_ret_cond);
    pthread_mutex_destroy(&ctrl.set_volume_mutex);

    pthread_mutex_destroy(&sys_state.display_mutex);

    // 释放MP3文件列表
    if(mp3_files.files) {
        free_file_list(mp3_files.files);
    }
}



// 线程信号处理函数
static void control_thread_handle_signal(int sig) {
    control_thread.exit_flag = 1;
}

// 设置音量
static int _setVolume(int db) {
    //禁止多线程重入
    if(! sys_state.current_pcm_player) 
        return 0;
    int rc;
    pthread_mutex_lock(&ctrl.set_volume_mutex);
    rc = sys_state.current_pcm_player->setVolume(db);
    pthread_mutex_unlock(&ctrl.set_volume_mutex);
    return rc;
}


/*
 * 读取一个输入字符，并跳过所有以 ESC 开头的转义序列
 * 返回非转义的有效字符，若读取错误则返回 ERR
 */
#define KEY_ERR -1
#define KEY_UP          0xff00
#define KEY_DOWN        0xff01
#define KEY_LEFT        0xff02
#define KEY_RIGHT       0xff03
#define KEY_HOME        0xff04
#define KEY_END         0xff05
#define KEY_PAGE_UP     0xff06
#define KEY_PAGE_DOWN   0xff07
#define KEY_DELETE      0xff08

static int getch(void) {
    int ch;
    while ((ch = getchar()) != KEY_ERR) {
        if(ch == 0x1B) {  // ESC 字符
            int next = getchar();
            if(next == '[') {  // 这是 CSI 转义序列
                int c;
                // 读取直到遇到CSI结束字符：终止字符在 '@' 到 '~' 之间
                c = getchar();
                //处理方向键
                if(c == 'A') return KEY_UP;
                if(c == 'B') return KEY_DOWN;
                if(c == 'C') return KEY_RIGHT;
                if(c == 'D') return KEY_LEFT;
                if(c == 'H') return KEY_HOME;
                if(c == 'F') return KEY_END;
                if(c == '5') {
                    c = getchar();
                    if(c == '~') return KEY_PAGE_UP;
                    if(c >= '@' && c <= '~')  break;
                }
                if(c == '6') {
                    c = getchar();
                    if(c == '~') return KEY_PAGE_DOWN;
                    if(c >= '@' && c <= '~')  break;
                }
                if(c == '3') {
                    c = getchar();
                    if(c == '~') return KEY_DELETE;
                    if(c >= '@' && c <= '~')  break;
                }
                if(c >= '@' && c <= '~')  break;
                while((c = getchar()) != KEY_ERR) {
                    if(c >= '@' && c <= '~')  break;
                }
            } else if(next == ']') {  // 这是 OSC 转义序列
                int c;
                // OSC 转义序列以 BEL (0x07) 结束，或以 ESC + '\' 结束
                while((c = getchar()) != KEY_ERR) {
                    if(c == 0x07) { // BEL
                        break;
                    }
                    if(c == 0x1B) { // 如果再次遇到 ESC，检测是否为结束标记的 ESC "\"
                        int c2 = getchar();
                        if(c2 == '\\')
                            break;
                    }
                }
            }
            // 对于其它以 ESC 开头的序列，直接跳过 next 也行
            // 这里不返回 ESC 本身，而是丢弃整个转义序列，继续读下一个字符
            continue;  
        } else {
            // 非 ESC 字符，直接返回
            return ch;
        }
    }
    return KEY_ERR;
}

static void display_ctrl_info(const char *file_name, int current_ms);
static void display_mp3_list(char **MP3files, int mp3_files_count, int current_mp3_file, int start);

// 控制线程
static ctrl_cmd_ret_t send_cmd_wait_return(ctrl_cmd_t cmd) {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += 5; // 等待5秒
    pthread_mutex_lock(&ctrl.cmd_mutex);
    ctrl.cmd = cmd;
    ctrl.cmd_ret = CTRL_CMD_RET_NONE;
    if((!player_state.is_playing) && (cmd == CTRL_CMD_PLAY || cmd == CTRL_CMD_PREV || cmd == CTRL_CMD_NEXT))
        pthread_cond_signal(&ctrl.cmd_play_cond);
    pthread_mutex_unlock(&ctrl.cmd_mutex);
    pthread_mutex_lock(&ctrl.cmd_ret_mutex);
    int ret = pthread_cond_timedwait(&ctrl.cmd_ret_cond, &ctrl.cmd_ret_mutex, &ts);
    pthread_mutex_unlock(&ctrl.cmd_ret_mutex);
    if (ret == ETIMEDOUT) {
        elog("send_cmd_wait_return timeout, cmd:%d\n", cmd);
        ctrl.cmd = CTRL_CMD_NONE;
        return CTRL_CMD_RET_ERR;
    }
    return ctrl.cmd_ret;
}

static void *control_thread_func(void *arg) {
    signal(SIGUSR1, control_thread_handle_signal);  // 注册信号处理
    
    while (!control_thread.exit_flag) {
        int ch = getch();
        bool update_ctrl = false, update_list = false;
        
        // Handle mute override for volume keys
        if ((ch == '+' || ch == '-') && player_state.mute) {
            ch = 'M';  // Convert to unmute if volume keys pressed while muted
        }
        
        switch (ch) {
            case '+':
                dlog("Volume +%d db\n", 5);
                player_state.volume = _setVolume(5);
                update_ctrl = true;
                break;        
            case '-':
                dlog("Volume %d db\n", -5);
                player_state.volume = _setVolume(-5);
                update_ctrl = true;
                break;
            case 'm': case 'M':
                player_state.mute = !player_state.mute;
                if (player_state.mute) {
                    ilog("Mute\n");
                    _setVolume(-100);
                } else {
                    ilog("Unmute\n");
                    for (int i = 0; i < 1000; i++) {
                        int volume = _setVolume(1);
                        if (volume >= player_state.volume) break;
                        delay_ms(1);
                    }
                    player_state.volume = _setVolume(0);
                }
                update_ctrl = true;
                break;
            case 'n': case 'N': case KEY_PAGE_DOWN:
                ilog("Next mp3 file\n");
                send_cmd_wait_return(CTRL_CMD_NEXT);
                break;
                
            case 'b': case 'B': case KEY_PAGE_UP:
                ilog("Prev mp3 file\n");
                send_cmd_wait_return(CTRL_CMD_PREV);
                break;
            case 'p': case 'P': case 0x20: // Space key
                if (player_state.is_playing) {
                    ilog("Pause mp3 file\n");
                    send_cmd_wait_return(CTRL_CMD_PAUSE);
                } else {
                    ilog("Play mp3 file\n");
                    send_cmd_wait_return(CTRL_CMD_PLAY);
                }          
                update_ctrl = 1;
                break;
            case 's': case 'S': case 'q': case 'Q': case 3: // CTRL-C
                ilog("Program terminated\n");
                exit(0);
                break;
            /*
            case 'f': case 'F': case KEY_RIGHT:
                ilog("Fast forward\n");
                send_cmd_wait_return(CTRL_CMD_FAST_FORWARD);
                break;
                
            case 'r': case 'R': case KEY_LEFT:
                ilog("Fast backward\n");
                send_cmd_wait_return(CTRL_CMD_FAST_BACKWARD);
                break;
            */
            default:
                break;
        }
        
        if (update_ctrl) {
            display_ctrl_info(mp3_files.files[player_state.current_mp3_no], player_state.current_mp3_ms);
        }
        if (update_list) {
            display_mp3_list(mp3_files.files, mp3_files.count, player_state.current_mp3_no, -1);
        }
    }
    
    return (void*)0;
}

static void *control_thread_func2(void *arg) {
    signal(SIGUSR1, control_thread_handle_signal);  // 注册信号处理
    
    while (!control_thread.exit_flag) {
        HeadsetButton button = get_headset_button();
        bool update_ctrl = false, update_list = false;
        
        switch (button) {
            case BUTTON_VOLINC:
                dlog("Volume +%d db\n", 5);
                player_state.volume = _setVolume(5);
                update_ctrl = true;
                break;
            case BUTTON_VOLDDEC:
                dlog("Volume %d db\n", -5);
                player_state.volume = _setVolume(-5);
                update_ctrl = true;
                break;
            case BUTTON_NEXT:
                ilog("Next mp3 file\n");
                send_cmd_wait_return(CTRL_CMD_NEXT);
                break;
            case BUTTON_PREV:
                ilog("Prev mp3 file\n");
                send_cmd_wait_return(CTRL_CMD_PREV);
                break;
            case BUTTON_PLAYPAUSE:
                if (player_state.is_playing) {
                    ilog("Pause mp3 file\n");
                    send_cmd_wait_return(CTRL_CMD_PAUSE);
                } else {
                    ilog("Play mp3 file\n");
                    send_cmd_wait_return(CTRL_CMD_PLAY);
                }          
                update_ctrl = 1;
                break;
            default:
                break;
        }
        
        if (update_ctrl) {
            display_ctrl_info(mp3_files.files[player_state.current_mp3_no], player_state.current_mp3_ms);
        }
        if (update_list) {
            display_mp3_list(mp3_files.files, mp3_files.count, player_state.current_mp3_no, -1);
        }
    }
    
    return (void*)0;
}

// 启动控制线程
static void start_control_thread(void) {
    pthread_create(&control_thread.id, NULL, control_thread.func, NULL);
    pthread_create(&control_thread.id2, NULL, control_thread.func2, NULL);

}

// 停止控制线程
static void stop_control_thread(void) {
    if(!control_thread_created()) return;
    pthread_kill(control_thread.id, SIGUSR1);
    pthread_kill(control_thread.id2, SIGUSR1);
    pthread_join(control_thread.id, NULL);
    pthread_join(control_thread.id2, NULL);
}

// 信号处理函数^C退出
static void handle_signal(int signal) {
    if (signal == SIGINT) {
        printf("\nProgram terminated with Ctrl-C\n");
        stop_control_thread();
        exit(0);
    }
}


// 显示控制信息
static char *ctrl_keys_info;  // 控制键信息
static void display_ctrl_info(const char *file_name, int current_ms) {
    pthread_mutex_lock(&sys_state.display_mutex);
    int ctrl_volume = player_state.volume;
    int total_ms = floor(player_state.mp3_info.duration * 1000);
    printf("\033[s\033[?25l"); // 保存光标位置并隐藏光标
    printf("\033[1;1H\033[2K\033[2;1H\033[2K"); // 清除第 1 行和第 2 行
    printf("\033[1;1H\033[32m>>>TIME:%03d.%03ds/%03d.%03ds | 采样率:%03d.%03dk| VOL:%03d%s| %s [%d/%d] %-20s \033[0m", 
        current_ms/1000, current_ms %1000, total_ms/1000, total_ms%1000, player_state.mp3_info.sample_rate/1000,player_state.mp3_info.sample_rate%1000, player_state.volume, (player_state.mute?"🔇":" "), (player_state.is_playing?"▶️":"⏸️"), 
        player_state.current_mp3_no+1, mp3_files.count, (file_name ? file_name : "无文件"));
    printf("\033[2;1H\033[32m>>>%s\033[0m", ctrl_keys_info);
    printf("\033[u\033[?25h"); // 恢复光标位置并显示光标
    fflush(stdout);
    pthread_mutex_unlock(&sys_state.display_mutex);
}


// 显示MP3文件列表
static void display_mp3_list(char **MP3files, int mp3_files_count, int current_mp3_file, int start) {
    pthread_mutex_lock(&sys_state.display_mutex);
    int cols = sys_state.scrsize.ws_col;
    if(cols > 100) cols = 100;  // 最大100列
    char divider[cols*3 + 1];
    const char utf8_dash[] = "─"; //3 bytes
    //复制utf8_dash到divider，复制sys_state.scrsize.ws_col次
    for(size_t i=0; i< cols*3; i+=3) {
        memcpy(divider + i, utf8_dash, 3);
    }
    divider[cols*3] = '\0';
    // 保存光标位置并隐藏光标
    printf("\033[s\033[?25l");
    int pos_y = UI_HEIGHT_CTRL;
    printf("\033[%d;1H\033[K", pos_y); // 定位到指定行并清除行
    printf("%s", "文件名");                              // 显示当前播放的MP3文件
    printf("\033[%d;%dH%s", pos_y, 30, "标题");  // 输出ID3v2标题‌
    printf("\033[%d;%dH%s", pos_y, 50, "专辑");  // 输出ID3v2专辑‌
    printf("\033[%d;%dH%s", pos_y, 70, "艺术家");  // 输出ID3v2艺术家‌
    printf("\033[%d;%dH%10s", pos_y, 90, "年份");  // 输出ID3v2年份
    pos_y++;
    printf("\033[%d;1H\033[K%s", pos_y, divider); // 定位到指定行并清除行,显示分割线
    pos_y++;

    int lines = sys_state.scrsize.ws_row - UI_HEIGHT_CTRL - UI_HEIGHT_LOG - 3;
    if(lines < 1) lines = 1; //至少显示一行, 避免lines负数出现死循环

    int display_item;
    if(start >=0)  {
        display_item = start;
    } else {
        display_item = player_state.current_mp3_no - lines/2;
    }
    if(display_item < 0) display_item = 0;
    
    int display_end = display_item + lines;
    if(display_end >= mp3_files_count) display_end = mp3_files_count-1;

    // 动态显示区间内的文件
    while (lines--) {
        printf("\033[%d;1H\033[K", pos_y);  // 定位到指定行并清除行
        if(display_item <= display_end && display_item < mp3_files_count) {
            char *file_path = MP3files[display_item];
            if(!file_path) {
                display_item++;
                continue;
            }            
            // 解析ID3v2
            size_t id3_size = 0;
            id3v2_important_info_t id3v2_info = {0};
            FILE *mp3_file = fopen(file_path, "rb");
            if(mp3_file) {
                printf("\033[u\033[?25h"); // 恢复光标位置并显示光标, 让parse_id3v2 正常输出log
                id3_size = parse_id3v2(mp3_file, &id3v2_info, false);
                printf("\033[s\033[?25l"); // 保存光标位置并隐藏光标
                fclose(mp3_file);
            }
            
            if (display_item == player_state.current_mp3_no) {
                printf("\033[1;33m");                                   // 设置高亮
            }
            char file_dir[PATH_MAX];
            char file_name[PATH_MAX];
            split_path(file_path, file_dir, file_name);
            printf("\033[%d;%dH%s", pos_y, 0, file_name);  // 显示当前播放的MP3文件
            printf("\033[%d;%dH%s", pos_y, 30, id3v2_info.title);  // 输出ID3v2标题‌
            printf("\033[%d;%dH%s", pos_y, 50, id3v2_info.album);  // 输出ID3v2专辑‌
            if(id3v2_info.track[0] != '\0') {
                printf("@%s", id3v2_info.track);  // 输出ID3v2曲目
            }
            printf("\033[%d;%dH%s", pos_y, 70, id3v2_info.artist);  // 输出ID3v2艺术家‌
            printf("\033[%d;%dH%10s", pos_y, 90, id3v2_info.year);  // 输出ID3v2年份
            if (display_item == player_state.current_mp3_no) {
                printf("\033[0m");                                // 恢复默认颜色
            }

            display_item++;
        }
        pos_y++;
    }
    //显示分割线
    printf("\033[%d;1H\033[K%s", pos_y++, divider); // 定位到指定行并清除行,显示分割线
    // 恢复光标位置并显示光标
    printf("\033[u\033[?25h");
    fflush(stdout);
    pthread_mutex_unlock(&sys_state.display_mutex);
}  


static void sigwinch_handler(int sig)
{
    int rc = init_screen();
    if(rc != 0) {
        elog("init_screen failed\n");
        return;
    }
    display_ctrl_info(mp3_files.files[player_state.current_mp3_no], player_state.current_mp3_ms);
    display_mp3_list(mp3_files.files, mp3_files.count, player_state.current_mp3_no, -1);
}


static void cmd_result(ctrl_cmd_ret_t ret) {
    pthread_mutex_lock(&ctrl.cmd_ret_mutex);
    ctrl.cmd_ret = ret;
    pthread_cond_signal(&ctrl.cmd_ret_cond);
    ctrl.cmd = CTRL_CMD_NONE;
    pthread_mutex_unlock(&ctrl.cmd_ret_mutex);
}

// 播放一个mp3文件
static int  play_mp3(const char *path, const char *file_name) {
    pcm_player_t * current_pcm_player = sys_state.current_pcm_player;
    if(!current_pcm_player) {
        elog("current_pcm_player is NULL\n");
        return -1;
    }
    char file_path[PATH_MAX];
    snprintf(file_path, sizeof(file_path), "%s%c%s", path, PATH_SEPARATOR, file_name);
    FILE *mp3_file = fopen(file_path, "rb");
    if (!mp3_file) {
        printf("Unable to open file %s,error:%s\n", file_path, strerror(errno));
        return -2;
    }

    // 解析ID3v2
    size_t id3_size = 0;
    id3_size = parse_id3v2(mp3_file, &player_state.id3v2_info, true);
    fseek(mp3_file, id3_size, SEEK_SET); // 跳过ID3v2

    // 获取MP3信息
    mp3_info_t* mp3_info = &player_state.mp3_info;
    if(!get_mp3_info(mp3_file, mp3_info, true)) {
        elog("get_mp3_info failed\n");
        return -3;
    }
    if(mp3_info->channels == 0 || mp3_info->sample_rate == 0) {
        elog("get_mp3_info failed\n");
        return -3;
    }
    ilog("MP3 channels %d samplerate %d\n", mp3_info->channels, mp3_info->sample_rate);

    // 使用从MP3信息中获取的参数初始化PCM播放器
    if(current_pcm_player->init(mp3_info->channels, mp3_info->sample_rate, 16) != 0) {
        elog("pcmPlayer_init failed\n");
        return -4;
    }

    // 获取实际设置的参数（可能与请求的不同）
    int channels, samplerate, bits_per_sample;
    current_pcm_player->getParams(&channels, &samplerate, &bits_per_sample);
    ilog("sound hw channels %d samplerate %d\n", channels, samplerate);
    
    // 初始化播放状态
    player_state.volume = _setVolume(0);
    player_state.current_mp3_ms = 0;
    player_state.mute = false;
    player_state.is_playing = true;
        
    int rc = 0;  // 返回值
    struct mad_stream stream;
    struct mad_frame frame;
    struct mad_synth synth;
    mad_timer_t timer;
    unsigned char input_buffer[8192];
    unsigned char output_buffer[8192 * 4];
    size_t input_size;

    // Initialize libmad
    mad_stream_init(&stream);
    mad_frame_init(&frame);
    mad_synth_init(&synth);

    int remain = 0;
    int read_size = 0;
    mad_timer_reset(&timer);

    int last_ms = 0;
    while (true) {
        if(remain >0) {
            memmove(input_buffer, input_buffer + sizeof(input_buffer) - remain, remain);
            read_size = fread(input_buffer + remain , 1, sizeof(input_buffer) - remain, mp3_file);
            if(read_size <= 0) break;
            input_size = remain + read_size;
        } else {
            read_size = fread(input_buffer, 1, sizeof(input_buffer), mp3_file);
            if(read_size <= 0) break;
            input_size = read_size;
        }
        if (input_size == 0) break; 
        mad_stream_buffer(&stream, input_buffer, input_size);
        while (true) {
            //if(ctrl.cmd == CTRL_CMD_FAST_FORWARD) {
            //    // 快进
            //    remain = 0;
            //    cmd_result(CTRL_CMD_RET_OK);
            //    break;
            //}
            //if(ctrl.cmd == CTRL_CMD_FAST_BACKWARD) {
            //    // 快退
            //    fseek(mp3_file, -10 * sizeof(input_buffer), SEEK_CUR);
            //    cmd_result(CTRL_CMD_RET_OK);
            //    break;
            //}
            if(ctrl.cmd == CTRL_CMD_PAUSE) {
                // 暂停
                if(current_pcm_player->ctrl) current_pcm_player->ctrl(PLAYER_CMD_PAUSE, NULL);
                player_state.is_playing = false;
                cmd_result(CTRL_CMD_RET_OK);
                
                pthread_mutex_lock(&ctrl.cmd_mutex);
                pthread_cond_wait(&ctrl.cmd_play_cond, &ctrl.cmd_mutex);
                pthread_mutex_unlock(&ctrl.cmd_mutex);

                if(ctrl.cmd == CTRL_CMD_PLAY) {
                    if(current_pcm_player->ctrl) current_pcm_player->ctrl(PLAYER_CMD_RESUME, NULL);
                    player_state.is_playing = true;
                    cmd_result(CTRL_CMD_RET_OK);
                }
            }

            if(ctrl.cmd == CTRL_CMD_NEXT || ctrl.cmd == CTRL_CMD_PREV || ctrl.cmd == CTRL_CMD_STOP) {
                if(current_pcm_player->ctrl) current_pcm_player->ctrl(PLAYER_CMD_STOP, NULL);
                rc = ctrl.cmd;
                cmd_result(CTRL_CMD_RET_OK);
                goto cleanup;
            }

            int RC = mad_frame_decode(&frame, &stream);
            //dlog("MAD frame decode :%u , frame: %u , remain: %u\n", 
            //    stream.this_frame - stream.buffer , stream.next_frame - stream.this_frame , stream.bufend - stream.next_frame);
            remain = stream.bufend - stream.next_frame;
            if (RC != 0) {
                //dlog("MAD frame decode error:%s(%u)\n", mad_stream_errorstr(&stream), stream.error);
                if (MAD_RECOVERABLE(stream.error)) {
                    //elog("Recoverable frame error\n");
                    printf("E");
                    continue;
                } else if (stream.error == MAD_ERROR_BUFLEN) {
                    break;
                } else {
                    //elog("Unrecoverable frame error: %s\n", mad_stream_errorstr(&stream));
                    printf("U");
                    break;
                }
            }

            mad_timer_add(&timer, frame.header.duration);
            player_state.current_mp3_ms = mad_timer_count(timer, MAD_UNITS_MILLISECONDS);
            if(last_ms > player_state.current_mp3_ms) {
                // 处理时间回退或越界
                last_ms = player_state.current_mp3_ms;
            }
            if((player_state.current_mp3_ms > 0) && (player_state.current_mp3_ms - last_ms >= 1000)) {
                // 每秒更新一次播放时间和音量等信息
                display_ctrl_info(file_name, player_state.current_mp3_ms);
                last_ms = player_state.current_mp3_ms;
            }
            
            mad_synth_frame(&synth, &frame);

            unsigned char *output_ptr = output_buffer;
            for (int i = 0; i < synth.pcm.length; i++) {
                signed int sample;

                sample = scale(synth.pcm.samples[0][i]);
                *(output_ptr++) = sample & 0xff;
                *(output_ptr++) = (sample >> 8) & 0xff;

                if (channels == 2) {
                    sample = scale(synth.pcm.samples[1][i]);
                    *(output_ptr++) = sample & 0xff;
                    *(output_ptr++) = (sample >> 8) & 0xff;
                }
            }
            RC = current_pcm_player->write(output_buffer, (output_ptr - output_buffer));
            if(RC != 0) {
                elog("pcmPlayer_write failed, player paused\n");
                ctrl.cmd = CTRL_CMD_PAUSE;
                player_state.is_playing = false;
            }
        }
    }

    // Clean up
    cleanup:
    player_state.is_playing = 0;
    mad_synth_finish(&synth);
    mad_frame_finish(&frame);
    mad_stream_finish(&stream);
    current_pcm_player->deinit();
    fclose(mp3_file);
    return rc;
}


int pcmPlayer_register(pcm_player_t *pcm_player) {
    sys_state.pcm_players =  realloc(sys_state.pcm_players, sizeof(pcm_player_t *) * (sys_state.pcm_players_count + 1));
    sys_state.pcm_players[sys_state.pcm_players_count++] = pcm_player;
    return 0;
}

static void print_help(const char *prog_name) {
    printf("Usage: %s [options] mp3_path\n", prog_name);
    printf("Options:\n");
    printf("  -h, --help     Display help information\n");
    printf("  -v, --verbose  Enable verbose mode\n");
    printf("  -t [num]       Specify PCM player no\n");
    for(int i = 0; i < sys_state.pcm_players_count; i++) {
        printf("       %d   -     %s\n", i+1, sys_state.pcm_players[i]->name);
    }
    printf("  mp3_path       MP3 file or directory\n");
}

static char *ctrl_keys_info = "+- : 🔉Volume, B: ⏮️Prev, N: ⏭️Next, P: Pause/Play, S/Q: Stop/Quit";


int main(int argc, char *argv[]) {

    printf("Mini mp3-player Version: %s\n", PLAYER_VERSION ", Built: "  __DATE__  " " __TIME__);

    int verbose = 0;
    int player_num = 0;
    char *mp3_path = NULL;
    if(argc <2) {
        print_help(argv[0]);
        return 1;
    }
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            print_help(argv[0]);
            return 0;
        }
        else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
            verbose = 1;
        }
        else if (strcmp(argv[i], "-t") == 0) {
            if (i + 1 < argc) {
                player_num = atoi(argv[++i]);
                if(player_num <= 0 || player_num > sys_state.pcm_players_count) {
                    printf("error: -t Specify PCM player no\n");
                    print_help(argv[0]);
                    return 1;
                }   
            } else {
                printf("error: -t Specify PCM player no\n");
                print_help(argv[0]);
                return 1;
            }
        }
        else if(argv[i][0] == '-'){
            printf("unknown option: %s\n", argv[i]);
            print_help(argv[0]);
            return 1;
        }
        else {
            if(!mp3_path) mp3_path = argv[i];
            else {
                printf("too many arguments\n");
                print_help(argv[0]);
                //return 1;
            }
        }
    }

    if(sys_state.pcm_players_count == 0) {
        elog("No PCM player found\n");
        return 1;
    }
    ilog("find %d pcm players\n", sys_state.pcm_players_count);
    // 选择一个指定或默认的PCM设备
    for(int i = 0; i < sys_state.pcm_players_count; i++) {
        printf("\t[%d]%s", i+1,  sys_state.pcm_players[i]->name);
        if(sys_state.pcm_players[i]->check()) {
            if(player_num == 0) {
                if(!sys_state.current_pcm_player) {
                    sys_state.current_pcm_player = sys_state.pcm_players[i];
                    printf(" (default)");
                }
                printf(" (avail)");
            }  else if(player_num == i+1) {
                sys_state.current_pcm_player = sys_state.pcm_players[i];
                printf(" (avail)");
                printf(" (selected)");                
            } else {
                printf(" (avail)");
            }

        } else {
            printf(" (not avail)");
            if(player_num == i+1) printf(" (selected)");
        }
        printf("\n");
    }

    if(!sys_state.current_pcm_player) {
        elog("No PCM player selected\n");
        return 1;
    }

    // 初始化
    int rc = init();
    if(rc != 0) {
        elog("init failed\n");
        return rc;
    }
    // 启动控制线程
    start_control_thread();
    // 注册信号处理函数，处理Ctrl-C，实际已经在控制线程中处理
    signal(SIGINT, handle_signal);

    // 查找mp3文件
    mp3_files.files = list_files(mp3_path, "*.mp3", &mp3_files.count);

    if(mp3_files.count == 0) {
        elog("No mp3 files found\n");
        return 1;
    } else {
        ilog("find %d mp3 files\n", mp3_files.count);
    }


    // 播放mp3文件
    while(1) {
        char dir_part[PATH_MAX];
        char file_part[PATH_MAX];
        display_ctrl_info(mp3_files.files[player_state.current_mp3_no], 0);
        display_mp3_list(mp3_files.files, mp3_files.count, player_state.current_mp3_no, -1);
        split_path(mp3_files.files[player_state.current_mp3_no], dir_part, file_part);
        ilog("mp3 file: %s\n", file_part);
        int rc = play_mp3(dir_part, file_part);
        if(rc == CTRL_CMD_STOP) break;
        if(rc <= 0 || rc == CTRL_CMD_NEXT) {  // 播放完毕或错误，或按键控制播放下一个
            if(player_state.current_mp3_no < mp3_files.count - 1) {
                player_state.current_mp3_no++;
            } else {
                player_state.current_mp3_no = 0;
            }
        } else if(rc == CTRL_CMD_PREV) {
            if(player_state.current_mp3_no > 0) {
                player_state.current_mp3_no--;
            } else {
                player_state.current_mp3_no = mp3_files.count  - 1;
            }
        }
    }
    // 停止控制线程
    printf("press any key to exit\n");
    stop_control_thread();
    
    return 0;
}